﻿using HtmlAgilityPack;
using Microsoft.WindowsAPICodePack.Taskbar;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading.Tasks;
using System.Xml;
using iTextSharp.text.pdf;

namespace Huknow
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            TaskbarManager taskbarman = TaskbarManager.Instance;
            ResetWindow();
        }

        private bool IsViewerMode = false;// property?
        private GridLength StoreColumn0 = GridLength.Auto;
        private GridLength StoreColumn2 = GridLength.Auto;
        private GridLength StoreRow2 = GridLength.Auto;

        private HtmlDocument HtmlContent = null;
        private int CountOfNodesOfHtmlContent = 0;

        private ProgressBar ProgressBuildingContentTree = null;
        private ProgressBar ProgressBuildingSections = null;

        private async void RenderWebPage(string p)
        {
            HtmlDocument htmlDoc = await PrepareHtml(p);

            HtmlContent = htmlDoc;
            CountOfNodesOfHtmlContent = CountOfChildren(HtmlContent.DocumentNode) + 1;

            TreeViewItem treeItem = new TreeViewItem();
            treeItem.Header = GetNameAndStat(htmlDoc.DocumentNode);
            treeItem.Tag = htmlDoc.DocumentNode;
            InitProgressBuildingContentTree();
            new Task(() =>
            {
                RenderHtmlNode(htmlDoc.DocumentNode, treeItem, true);
                //PageTreeView.Items.Add(treeItem);
                this.Dispatcher.Invoke(() =>
                {
                    PageTreeView.ItemsSource = new List<TreeViewItem>() { treeItem };
                    PageTreeView.Visibility = System.Windows.Visibility.Visible;
                }, System.Windows.Threading.DispatcherPriority.Loaded);
            }, TaskCreationOptions.LongRunning).Start();

            //PolyLineSegment segs = new PolyLineSegment();
            //segs.Points.Add(new Point(1000, 50));
            //segs.Points.Add(new Point(100, 1000));
            //segs.Points.Add(new Point(50, 1000));
            //PathSegmentCollection segCol = new PathSegmentCollection();
            //segCol.Add(segs);
            //PathFigure fig = new PathFigure(new Point(0, 0), segCol, true);
            //PathFigureCollection fgs = new PathFigureCollection();
            //fgs.Add(fig);
            //PathGeometry geom = new PathGeometry(fgs, FillRule.EvenOdd, null);
            //Path path = new Path();
            //path.Data = geom;
            //path.Fill = Brushes.Black;
            //path.Stroke = Brushes.Blue;
            //path.StrokeThickness = 1;
            //PageCanvas.Children.Add(path);

            InitProgressBuildingSections();
            Section section = new Section();
            new Task(() =>
            {
                FormatNodeContent(htmlDoc.DocumentNode, section); // Fill node2sec. maybe usign XamlWriter/XamlReader?
            }, TaskCreationOptions.LongRunning).Start();

            //StringWriter strBuf = new StringWriter();
            //htmlDoc.Save(strBuf);
            //string htmlText = new StringReader(strBuf.GetStringBuilder().ToString()).ReadToEnd();

            FrameworkElement viewer = null;
            switch ((string)ComboHtmlViewer.SelectedValue)
            {
                case "WebBrowser":
                    WebBrowser webBrowser = new WebBrowser();
                    //await Task.Run(() => { 
                    webBrowser.NavigateToString(p);
                    //});
                    viewer = webBrowser;
                    break;

                case "HtmlRenderer":
                    //viewer = await Task.Run < TheArtOfDev.HtmlRenderer.WPF.HtmlPanel>(() =>
                    //{
                    TheArtOfDev.HtmlRenderer.WPF.HtmlPanel htmlPanel = new TheArtOfDev.HtmlRenderer.WPF.HtmlPanel();
                    htmlPanel.Text = p;
                    //return htmlPanel;
                    //});
                    viewer = htmlPanel;
                    break;

                case "MyFlowDocument":
                    //string flowDoc = ConvertHtmlDocumentToXamlDocument(htmlDoc);// HtmlToXamlConvert.HtmlToXamlConverter.ConvertHtmlToXaml(p, true);
                    //viewer = new RichTextBox((FlowDocument)XamlReader.Parse(flowDoc)) { IsReadOnly = true, HorizontalScrollBarVisibility = ScrollBarVisibility.Visible, VerticalScrollBarVisibility = ScrollBarVisibility.Visible };
                    viewer = new RichTextBox(new FlowDocument(ConvertHtmlDocumentToXamlDocument(htmlDoc))) { IsReadOnly = true, HorizontalScrollBarVisibility = ScrollBarVisibility.Visible, VerticalScrollBarVisibility = ScrollBarVisibility.Visible };
                    break;

                case "MSFlowDocument":
                    string flowDoc = HtmlToXamlConvert.HtmlToXamlConverter.ConvertHtmlToXaml(p, true);
                    viewer = new RichTextBox((FlowDocument)XamlReader.Parse(flowDoc)) { IsReadOnly = true, HorizontalScrollBarVisibility = ScrollBarVisibility.Visible, VerticalScrollBarVisibility = ScrollBarVisibility.Visible };
                    break;


                case "Awesomium":
                    viewer = new Awesomium.Windows.Controls.WebControl();
                    ((Awesomium.Windows.Controls.WebControl)viewer).Source = new Uri(AddressBox.Text);//.LoadHTML(p);
                    break;

                default:
                    //viewer = null;
                    break;
            }

            int i = (viewer != null) ? ViewerGrid.Children.Add(viewer) : 0;
            ViewerGrid.Visibility = System.Windows.Visibility.Visible;
            //string xaml = XamlWriter.Save(viewer);
            //viewer.Margin = new Thickness(0.0);
        }

        private int CountOfChildren(HtmlNode htmlNode)
        {
            return htmlNode.ChildNodes.Aggregate(htmlNode.ChildNodes.Count, (S, n) => { return S + CountOfChildren(n); });
        }

        private void InitProgressBuildingSections()
        {
            ProgressBuildingSections = new ProgressBar();
            ProgressBuildingSections.Maximum = CountOfNodesOfHtmlContent;
            ProgressBuildingSections.Height = 12;

            Grid panel = new Grid();
            TextBlock text = new TextBlock(new Run("Build sections"));
            panel.Children.Add(ProgressBuildingSections);
            panel.Children.Add(text);
            
            Binding bind = new Binding(@"ActualWidth");
            bind.Source = ViewerGrid;
            bind.Mode = BindingMode.OneWay;
            panel.SetBinding(ProgressBar.WidthProperty, bind);

            Progresses.Items.Add(panel);
        }

        private void InitProgressBuildingContentTree()
        {
            ProgressBuildingContentTree = new ProgressBar();
            ProgressBuildingContentTree.Maximum = CountOfNodesOfHtmlContent;
            ProgressBuildingContentTree.Height = 12;

            Grid panel = new Grid();
            TextBlock text = new TextBlock(new Run("Build content tree"));
            panel.Children.Add(ProgressBuildingContentTree);
            panel.Children.Add(text);

            Binding bind = new Binding(@"ActualWidth");
            bind.Source = ViewerGrid;
            bind.Mode = BindingMode.OneWay;
            panel.SetBinding(ProgressBar.WidthProperty, bind);

            Progresses.Items.Add(panel);
        }

        private Block ConvertHtmlDocumentToXamlDocument(HtmlDocument htmlDoc)
        {
            Block r = (Block)ConvertHtmlNodeToXamlNode(htmlDoc.DocumentNode);
            return r;
        }

        private Section ConvertHtmlNodeToXamlNode(HtmlNode htmlNode)
        {
            if (htmlNode.NodeType == HtmlNodeType.Comment)
            {
                return null;
            }

            //Section elem = new Section() { Margin = new Thickness(10.0), BorderBrush = Brushes.Black, BorderThickness = new Thickness(1.0) };
            Section elem = new Section() { Margin = new Thickness(0.0) };
            bool isUnknown = false;
            //bool deepToChilds = true;

            if (htmlNode.NodeType == HtmlNodeType.Text)
            {
                //htmlNode.SelectSingleNode();
                if (!htmlNode.XPath.Contains("title") && !htmlNode.XPath.Contains("script"))
                    elem.Blocks.Add(new Paragraph(new Run(htmlNode.InnerText)) { Margin = new Thickness(0.0) });
                return elem;
            }

            if (htmlNode.NodeType == HtmlNodeType.Element)
            {
                switch (htmlNode.Name)
                {
                    case "html":
                        //
                        break;

                    case "head":
                        break;

                    case "body":
                        break;

                    case "title":
                        //deepToChilds = false;
                        break;

                    case "link":
                        break;

                    case "meta":
                        break;

                    case "base":
                        break;

                    case "script":
                        //deepToChilds = false;
                        break;

                    case "noscript":
                        break;

                    case "div":
                        break;

                    case "table":
                        break;

                    case "tr":
                        break;

                    case "td":
                        //elem.BreakColumnBefore = false;
                        break;

                    case "a":
                        break;

                    case "img":
                        break;

                    case "p":
                        break;

                    case "span":
                        break;

                    case "form":
                        break;

                    case "input":
                        break;

                    case "hr":
                        break;

                    case "ul":
                        break;

                    case "li":
                        break;

                    case "b":
                        break;

                    case "i":
                        break;

                    case "br":
                        break;

                    case "label":
                        break;

                    case "h1":
                        break;

                    case "h2":
                        break;

                    case "h3":
                        break;

                    case "h4":
                        break;

                    case "wbr":
                        break;

                    case "header":
                        break;

                    case "footer":
                        break;

                    case "button":
                        break;

                    case "nav":
                        break;

                    case "section":
                        break;

                    case "strong":
                        break;

                    case "em":
                        break;

                    case "dl":
                        break;

                    case "dt":
                        break;

                    case "dd":
                        break;

                    case "center":
                        break;

                    case "font":
                        break;

                    case "noindex":
                        break;

                    default:
                        elem.Blocks.Add(new Paragraph(new Run(String.Format(@"<{0}>", htmlNode.Name)) { Foreground = Brushes.Red }) { Margin = new Thickness(0.0) });
                        isUnknown = true;
                        break;
                }
            }

            //if(deepToChilds)
            foreach (HtmlNode node in htmlNode.ChildNodes)
            {
                Section e = ConvertHtmlNodeToXamlNode(node);
                if (e != null) elem.Blocks.Add(e);
            }
            
            if (isUnknown) elem.Blocks.Add(new Paragraph(new Run(String.Format(@"</{0}>", htmlNode.Name)) { Foreground = Brushes.Red }) { Margin = new Thickness(0.0) });

            if (elem.Blocks.Count == 0) return null;// elem.LineHeight = 0.004;
            return elem;
        }

        private async Task<HtmlDocument> PrepareHtml(string html)
        {
            return await Task.Run<HtmlDocument>(() => 
            {
                HtmlDocument htmlDoc = new HtmlDocument();
                htmlDoc.LoadHtml(html);

                List<HtmlNode> nodes = htmlDoc.DocumentNode.Descendants().Where((x) => { return x.NodeType == HtmlNodeType.Text; }).ToList();
                nodes.ForEach((x) => 
                {
                    if (x.InnerText.All((y) => { return Char.IsWhiteSpace(y); }))
                    {
                        x.Remove();
                    }
                });

                return htmlDoc;
            });
        }

        private void RenderHtmlNode(HtmlNode htmlNode, TreeViewItem item, bool moreDeep = false)
        {
            // BeginUpdate
            foreach (HtmlNode node in htmlNode.ChildNodes)
            {
                //if (node.NodeType != HtmlNodeType.Text)
                {
                    TreeViewItem tree_Item = this.Dispatcher.Invoke<TreeViewItem>(() =>
                    {
                        TreeViewItem treeItem = new TreeViewItem();
                        treeItem.Header = GetNameAndStat(node);
                        treeItem.Tag = node;
                        return treeItem;
                    }, System.Windows.Threading.DispatcherPriority.Loaded);
                    
                    if (moreDeep) RenderHtmlNode(node, tree_Item, true);
         
                    this.Dispatcher.Invoke(() =>
                    {
                        item.Items.Add(tree_Item);
                    }, System.Windows.Threading.DispatcherPriority.Loaded);
                }
            }
            // EndUpdate
            this.Dispatcher.Invoke(() =>
                {
                    ProgressBuildingContentTree.Value += 1;
                    UpdateSelectedProgressBar();
                }, System.Windows.Threading.DispatcherPriority.Loaded);
        }

        private void UpdateSelectedProgressBar()
        {
            //lock (Progresses)
            //{
            //    StackPanel bar = Progresses.Items.Cast<StackPanel>().First((n) => { return n.Value < n.Maximum; });
            //    if (bar != null)
            //    {
            //        Progresses.SelectedItem = bar;
            //    }
            //    else
            //    {
            //        Progresses.SelectedIndex = -1;
            //    }
            //}
        }

        private object GetNameAndStat(HtmlNode node)
        {
            StackPanel panel = new StackPanel() { Orientation = System.Windows.Controls.Orientation.Horizontal };
            int len = node.OuterHtml.Length;
            
            //return String.Format("{0} [{1}]", node.Attributes.Contains("id") ?
            //    String.Format("<{0}> {1}", node.Name, node.Attributes["id"].Value) :
            //    node.Name, len);

            switch(node.NodeType)
            {
                case HtmlNodeType.Comment:
                case HtmlNodeType.Document:
                case HtmlNodeType.Text:
                    Label lblText = new Label() { Content = node.Name };
                    lblText.Foreground = Brushes.Green;
                    panel.Children.Add(lblText);
                    break;

                case HtmlNodeType.Element:
                    Label lblElem = new Label() { Content = node.Attributes.Contains("id") ? String.Format("<{0}> {1}", node.Name, node.Attributes["id"].Value) : node.Name };
                    lblElem.Foreground = Brushes.Blue;
                    panel.Children.Add(lblElem);
                    break;

                default:
                    break;
            }

            Label lblLen = new Label() { Content = String.Format("[{0}]", len) };
            panel.Children.Add(lblLen);

            return panel;
        }

        public void ViewWebPage(string address)
        {
            KindOfAddress kind = GetKindOfAddress(address);

            string sysInfo = null;
            if ((sysInfo = ((App)Application.Current).TryInvokeNetInformation(address)) != null)
            {
                ResetWindow();
                RenderWebPage(sysInfo);
                return;
            }

            Uri addr = null;
            if (Uri.TryCreate(address, UriKind.Absolute, out addr))
            {
                ViewWebPage(addr);
            }
            else
            {
                addr = new Uri(String.Format(@"http://www.google.com/search?q={0}", address));
                ViewWebPage(addr);
            }
        }

        private KindOfAddress GetKindOfAddress(string address)
        {
            return KindOfAddress.Web;
        }

        public async void ViewWebPage(Uri address)
        {
            BaseUriPriorPage = address;
            ResetWindow();

            CurrentWebClientStatus.Content = String.Format("Download {0}", address.AbsoluteUri);

            HuknowInfo info = await(Application.Current as App).DownloadInfoTaskAsync(address);

            if (IsPDFile(info))
            {
                info.Html = ConvertPdfToXml(info.Html);
            }

            RenderWebPage(info.Html);
            CurrentWebClientStatus.Content = null;
        }

        private string ConvertPdfToXml(string p)
        {
            return ListFieldNames(p);
        }

        private bool IsPDFile(HuknowInfo info)
        {
            return info.Html[0] == '%' && info.Html[1] == 'P' && info.Html[2] == 'D' && info.Html[3] == 'F';
        }

        //declaration of function to check whether a form is xfa or pdf form
        public string ReadFieldnames(PdfReader reader)
        {
            AcroFields form = reader.AcroFields;
            XfaForm xfa = form.Xfa;
            StringBuilder sb = new StringBuilder();
            sb.Append(xfa.XfaPresent ? "XFA form" : "AcroForm");
            return sb.ToString();
        }

        //code to get the xml of the pdf in the textbox
        private string ListFieldNames(string pdfTemplate)
        {
            //this.Text += " - " + pdfTemplate;
            // create a new PDF reader based on the PDF template document

            PdfReader pdfReader = new PdfReader(System.Text.Encoding.UTF8.GetBytes(pdfTemplate));

            //checking the form is XFa form or not
            //String str = ReadFieldnames(pdfReader);
            //MessageBox.Show(str);

            XfaForm xfa = new XfaForm(pdfReader);
            System.Xml.XmlDocument doc = xfa.DomDocument;

            if (!string.IsNullOrEmpty(doc.DocumentElement.NamespaceURI))
            {
                doc.DocumentElement.SetAttribute("xmlns", "");
                System.Xml.XmlDocument new_doc = new System.Xml.XmlDocument();
                new_doc.LoadXml(doc.OuterXml);
                doc = new_doc;
            }

            StringBuilder sb = new StringBuilder();
            var Xsettings = new System.Xml.XmlWriterSettings() { Indent = true };
            using (var writer = System.Xml.XmlWriter.Create(sb, Xsettings))
            {
                doc.WriteTo(writer);
            }

            return sb.ToString();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            ResetWindow();
            base.OnClosing(e);
        }

        private void ResetWindow(bool IsFull = true)
        {
            //PageTreeView.Items.Clear();
            PageTreeView.ItemsSource = null;
            PageTreeView.Visibility = System.Windows.Visibility.Hidden;
            ChildGrid.ItemsSource = null;
            AttrGrid.ItemsSource = null;
            LinkGrid.ItemsSource = null;
            Tabs.Visibility = System.Windows.Visibility.Hidden;
            textHtml.Document.Blocks.Clear();// = null;// Clear();
            textHtml.Visibility = System.Windows.Visibility.Hidden;

            if (IsFull)
            {
                ViewerGrid.Children.Clear();
                ViewerGrid.Visibility = System.Windows.Visibility.Hidden;
                node2sec.Clear();
                HtmlContent = null;
                Progresses.Items.Clear();

                Task.Run(() => { GC.Collect(); });
            }

            Assembly a = Assembly.GetExecutingAssembly();
            this.Title = String.Format("{0} {1}", a.GetName().Name, a.GetName().Version.ToString());
        }

        public override void BeginInit()
        {
            base.BeginInit();
        }

        public override void EndInit()
        {
            base.EndInit();
        }

        private async void PageTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            if (e.NewValue is TreeViewItem)
            {
                TreeViewItem item = (TreeViewItem)e.NewValue;
                if ((item.Tag != null))// && (item.Tag is HtmlNode))
                {
                    HtmlNode node = (HtmlNode)item.Tag;
                    //if (node.NodeType == HtmlNodeType.Element)
                    {
                        AttrGrid.ItemsSource = node.Attributes;
                        Tabs.Visibility = System.Windows.Visibility.Visible;
                    }
                    //else
                    {
                        //System.Collections.Generic.List<object> listProps = new System.Collections.Generic.List<object>();

                        //foreach (PropertyInfo prop in node.GetType().GetProperties())
                        //{
                        //    listProps.Add(new { Property = prop.Name, Value = prop.GetValue(node, null) });
                        //}

                        //AttrGrid.ItemsSource = listProps;
                        ChildGrid.ItemsSource = node.ChildNodes;//.Where((x) => { return x.NodeType != HtmlNodeType.Text; });
                        Tabs.Visibility = System.Windows.Visibility.Visible;
                    }

                    HtmlNodeCollection coll = node.SelectNodes(SelPath.Text);//@".//*[@href]");
                    LinkGrid.ItemsSource = coll;
                    Tabs.Visibility = System.Windows.Visibility.Visible;

                    //string sXML = await CreateXmlOfNodeContent(node);
                    
                    //string sXML = await FormatNodeContent(node);
                    //Paragraph par = new Paragraph(new Run(sXML));

                    Section sec = new Section();
                    //FormatNodeContent(node, sec); 
                    node2sec.TryGetValue(node, out sec);
                    textHtml.Document = new FlowDocument(sec);// await CreateDocumentForBox(sb); ;//.Text = sb.ToString();// node.OuterHtml;
                    textHtml.Visibility = System.Windows.Visibility.Visible;

                    //if ((node.HasChildNodes) && (!item.HasItems))
                    //{
                    //    RenderHtmlNode(node, item, true);
                    //}
                }
            }
        }

        private Task<string> FormatNodeContent(HtmlNode node)
        {
            return Task.Run<string>(() =>
                {
                    StringBuilder sb = new StringBuilder(node.OuterHtml.Length + 1024);
                    FormatNodeContent(node, sb, 0);
                    return sb.ToString();
                });
        }

        private Dictionary<HtmlNode, Section> node2sec = new Dictionary<HtmlNode, Section>();

        private void FormatNodeContent(HtmlNode node, Section parent)
        {
            if ((node.NodeType == HtmlNodeType.Comment) || (node.NodeType == HtmlNodeType.Text))
            {
                this.Dispatcher.Invoke(() =>
                {
                    Section sec = new Section() { Margin = new Thickness(10.0, 0.0, 0.0, 0.0) };
                    Paragraph par = new Paragraph(new Run(node.InnerText));
                    par.Foreground = Brushes.Green;
                    par.Margin = new Thickness(0.0);
                    sec.Blocks.Add(par);
                    parent.Blocks.Add(sec);
                    node2sec.Add(node, sec);
                    ProgressBuildingSections.Value += 1;
                }, System.Windows.Threading.DispatcherPriority.Loaded);
                return;
            }

            List<Inline> attrs = this.Dispatcher.Invoke<List<Inline>>(() => { return FormatNodeAttributesAsInline(node); }, System.Windows.Threading.DispatcherPriority.Loaded);

            Section section = this.Dispatcher.Invoke<Section>(() =>
            {
                Section s = new Section() { Margin = new Thickness(10.0, 0.0, 0.0, 0.0) };

                Paragraph beforePar = new Paragraph();//new Run(String.Format(@"<{0}", node.Name)));
                beforePar.Inlines.Add(@"<");
                beforePar.Inlines.Add(new Run(node.Name) { Foreground = Brushes.DarkRed });
                beforePar.Inlines.AddRange(attrs);
                beforePar.Inlines.Add(node.HasChildNodes ? @">" : @"/>");
                beforePar.Foreground = Brushes.Blue;
                beforePar.Margin = new Thickness(0.0);
                s.Blocks.Add(beforePar);
                return s;
            }, System.Windows.Threading.DispatcherPriority.Loaded);

            //foreach (HtmlNode n in node.ChildNodes)
            Parallel.ForEach<HtmlNode>(node.ChildNodes, (n) =>
            {
                FormatNodeContent(n, section);
            });

            if (node.HasChildNodes)
            {
                this.Dispatcher.Invoke(() =>
                {
                    Paragraph afterPar = new Paragraph();//new Run(String.Format(@"</{0}>", node.Name)));
                    afterPar.Inlines.Add(@"</");
                    afterPar.Inlines.Add(new Run(node.Name) { Foreground = Brushes.DarkRed });
                    afterPar.Inlines.Add(@">");
                    afterPar.Foreground = Brushes.Blue;
                    afterPar.Margin = new Thickness(0.0);
                    section.Blocks.Add(afterPar);
                }, System.Windows.Threading.DispatcherPriority.Loaded);
            }

            this.Dispatcher.Invoke(() =>
            {
                parent.Blocks.Add(section);
                node2sec.Add(node, section);
                ProgressBuildingSections.Value += 1;
                UpdateSelectedProgressBar();
            }, System.Windows.Threading.DispatcherPriority.Loaded);
        }

        private List<Inline> FormatNodeAttributesAsInline(HtmlNode node)
        {
            List<Inline> list = new List<Inline>(node.Attributes.Count);
            if (!node.HasAttributes) return list;

            return node.Attributes.Aggregate<HtmlAttribute, List<Inline>, List<Inline>>(
                list,
                (l, a) => { 
                    //l.Add(new Run(String.Format(" {0}=\"{1}\"", a.Name, a.Value)) { Foreground = Brushes.Red }); 
                    l.Add(new Run(String.Format(@" {0}", a.Name)) { Foreground = Brushes.Red });
                    l.Add(new Run("=\"") { Foreground = Brushes.Blue });
                    l.Add(new Run(String.Format("{0}", a.Value)) { Foreground = Brushes.Blue, TextDecorations = ((a.Name == "href") || (a.Name == "src") ? TextDecorations.Underline : null) });
                    l.Add(new Run("\"") { Foreground = Brushes.Blue });
                    return l; },
                l => l
                );
        }

        private void FormatNodeContent(HtmlNode node, StringBuilder sb, int p)
        {
            string indent = new String('\t', p);

            if ((node.NodeType == HtmlNodeType.Comment) || (node.NodeType == HtmlNodeType.Text))
            {
                sb.Append(indent);
                sb.AppendLine(node.InnerText);
                return;
            }

            sb.AppendFormat(@"{0}<{1}{2}>", indent, node.Name, FormatNodeAttributes(node));
            sb.AppendLine();

            foreach (HtmlNode n in node.ChildNodes)
            {
                FormatNodeContent(n, sb, p + 1);
            }

            sb.AppendFormat(@"{0}</{1}>", indent, node.Name);
            sb.AppendLine();
        }

        private string FormatNodeAttributes(HtmlNode node)
        {
            if (!node.HasAttributes) return String.Empty;

            return node.Attributes.Aggregate<HtmlAttribute, string, string>(
                String.Empty,
                (r, a) => { return String.Format("{0} {1}=\"{2}\"", r, a.Name, a.Value); },
                r => r
                );
        }
         
        private Task<string> CreateXmlOfNodeContent(HtmlNode node)
        {
            return Task.Run<string>(() =>
                {
                    StringBuilder sb = new StringBuilder(node.OuterHtml.Length + 1024);
                    XmlWriterSettings settings = new XmlWriterSettings();
                    settings.OmitXmlDeclaration = true;
                    settings.IndentChars = "    ";
                    settings.Indent = true;
                    settings.ConformanceLevel = ConformanceLevel.Fragment;
                    using (XmlWriter xw = XmlTextWriter.Create(sb, settings))
                    {
                        try
                        {
                            node.WriteTo(xw);
                        }
                        catch (Exception E)
                        {
                            sb.Append(E.ToString());
                        }
                    }
                    return sb.ToString();
                    //return node.WriteTo();
                });
        }

        private Task<FlowDocument> CreateDocumentForBox(StringBuilder sb)
        {
            return Task.Run<FlowDocument>(() =>
                {
                    Paragraph par = new Paragraph(new Run(sb.ToString()));
                    return new FlowDocument(par);
                });
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            if ((PageTreeView.SelectedItem != null) && (PageTreeView.SelectedItem is TreeViewItem))
            {
                TreeViewItem item = (TreeViewItem)PageTreeView.SelectedItem;
                if ((item.Tag != null) && (item.Tag is HtmlNode))
                {
                    HtmlNode node = (HtmlNode)item.Tag;
                    if (node.Name == "a")
                    {
                        ViewWebPage(new Uri(BaseUriPriorPage, node.Attributes["href"].Value));
                    }
                }
            }
        }

        public Uri BaseUriPriorPage { get; set; }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var devices = SharpPcap.CaptureDeviceList.Instance;

            //PacketDotNet.Packet pack = PacketDotNet.EthernetPacket.RandomPacket();
            //PacketDotNet.Packet pack = PacketDotNet.IpPacket.RandomPacket(PacketDotNet.IpVersion.IPv4);
            //pack.Type = PacketDotNet.EthernetPacketType.Echo;
            //byte[] bytes = GetRandomPacket();
            PacketDotNet.Packet pack = PacketDotNet.IPv4Packet.RandomPacket(PacketDotNet.IpVersion.IPv4);

            SharpPcap.ICaptureDevice device = devices[0];
            device.Open();
            device.SendPacket(pack);
            device.Close();
        }

        private void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                ViewWebPage(AddressBox.Text);
            }
        }

        private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count > 0)
            {
                ContentControl ctrl = e.AddedItems[0] as ContentControl;
                AddressBox.Text = ctrl.Content as string;
            }
        }

        private void GoButton_Click(object sender, RoutedEventArgs e)
        {
            ViewWebPage(AddressBox.Text);
        }

        private void DoShowOrHide_Click(object sender, RoutedEventArgs e)
        {
            if (IsViewerMode)
            {
                WindowGrid.ColumnDefinitions[0].Width = StoreColumn0;
                WindowGrid.ColumnDefinitions[2].Width = StoreColumn2;
                WindowGrid.RowDefinitions[2].Height = StoreRow2;
                IsViewerMode = false;
            }
            else
            {
                StoreColumn0 = WindowGrid.ColumnDefinitions[0].Width;
                StoreColumn2= WindowGrid.ColumnDefinitions[2].Width;
                StoreRow2 = WindowGrid.RowDefinitions[2].Height;

                WindowGrid.ColumnDefinitions[0].Width = new GridLength(0.0);
                WindowGrid.ColumnDefinitions[2].Width = new GridLength(0.0);
                WindowGrid.RowDefinitions[2].Height = new GridLength(0.0);
                IsViewerMode = true;
            }
        }

        private void DoNewWindow_Click(object sender, RoutedEventArgs e)
        {
            (Application.Current as App).DoNewWindow();
        }

        private void DoOpenFile_Click(object sender, RoutedEventArgs e)
        {
            using (System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog())
            {
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    AddressBox.Text = ofd.FileName;
                    ViewWebPage(ofd.FileName);
                }
            }
        }

        private void SelPath_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                if (PageTreeView.SelectedItem != null)
                {
                    HtmlNode node = (HtmlNode)((TreeViewItem)PageTreeView.SelectedItem).Tag;
                    HtmlNodeCollection coll = node.SelectNodes(SelPath.Text);//@".//*[@href]");
                    LinkGrid.ItemsSource = coll;
                    Tabs.Visibility = System.Windows.Visibility.Visible;
                }
            }
        }

        private void SelElemByPath_KeyUp(object sender, KeyEventArgs e)
        {
            if ((e.Key == Key.Enter) && (HtmlContent != null))
            {
                ResetWindow(false);
                HtmlNodeCollection coll = HtmlContent.DocumentNode.SelectNodes(SelElemByPath.Text);
                List<TreeViewItem> items = new List<TreeViewItem>();
                if (coll != null)
                    foreach (HtmlNode node in coll)
                    {
                        TreeViewItem treeItem = new TreeViewItem();
                        treeItem.Header = GetNameAndStat(node);
                        treeItem.Tag = node;
                        new Task(() =>
                        {
                            RenderHtmlNode(node, treeItem, true);
                        }, TaskCreationOptions.LongRunning).Start();
                        //PageTreeView.Items.Add(treeItem);
                        items.Add(treeItem);
                    }
                PageTreeView.ItemsSource = items;
            }
        }

        private void MenuItem_Click_1(object sender, RoutedEventArgs e)
        {
            // TODO
        }

        private void DoTraceWorld_Click(object sender, RoutedEventArgs e)
        {
            (Application.Current as App).DoNewTraceWindow();
        }
    }
}

//        <WebBrowser x:Name="webBrowser" Grid.Column="1" Margin="10,79,10,0" Grid.Row="1" Height="43" VerticalAlignment="Top" RenderTransformOrigin="0.505,-0.613"/>
//        <wpf:HtmlPanel x:Name="htmlPageView" Grid.Column="1" Margin="10,10,10,0" Text="&lt;p&gt; &lt;h1&gt; Hello World &lt;/h1&gt; This is html rendered text&lt;/p&gt;" ScrollViewer.HorizontalScrollBarVisibility="Visible" Grid.Row="1" Height="34" VerticalAlignment="Top"/>
